﻿using System;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace SHomeWorkshop.LunarPresentation.Commands
{
    public partial class Command
    {
        public static void Paste(bool before = true)
        {
            String clipboardText = Clipboard.GetText(TextDataFormat.UnicodeText);
            if (clipboardText == null || clipboardText.Length == 0)
            {
                //如果没有文本，看看是否要粘贴图片框。
                Command.PasteImageFromClipboard();
                return;
            }

            if (Globals.selectedEditor == null) return;
            if (Globals.selectedEditor.SelectedExpression == null) return;

            Expressions.Expression curEx = Globals.selectedEditor.SelectedExpression;

            if (curEx is Expressions.LeafPanel)
            {
                if (clipboardText.StartsWith("<TreeLeaves") &&
                    clipboardText.EndsWith("</TreeLeaves>"))
                {
                    Command.PasteLeaf(); return;
                }

                //否则当作向普通子面板粘贴处理。
            }

            ModifingItem mi = new ModifingItem() { OldSelectedExID = curEx.ExID };

            if (curEx is Expressions.SubPanel)
            {
                //MessageBox.Show("不能把公式粘贴到“子面板”前面！", Globals.appName,
                //    MessageBoxButton.OK, MessageBoxImage.Warning);
                //return;//子面板不支持Paste。

                Expressions.SubPanel subPanel = curEx as Expressions.SubPanel;
                if (subPanel.BasePanel != null && subPanel.BasePanel.Children.Count > 0 &&
                    subPanel.BasePanel.Children[0] is Expressions.Expression)
                {
                    curEx = subPanel.BasePanel.Children[0] as Expressions.Expression;
                }
                else
                {
                    System.Windows.MessageBox.Show("子面板中无公式，无法执行粘贴公式操作！",
                        Globals.appName, System.Windows.MessageBoxButton.OK,
                        System.Windows.MessageBoxImage.Warning);
                    return;
                }
            }

            Expressions.Expression newEx = InsertExpressionByXmlString(before, clipboardText, curEx);

            #region 看看粘贴的是不是一个“树”，如果不是，直接递归重建所有公式的ID。

            Expressions.Tree tree = newEx as Expressions.Tree;
            if (tree == null)
            {
                Expressions.Expression.RebuildAllExIDs(newEx);//为避免重复的ExID，重建此公式及子级的所有ExID。
            }
            else
            {
                tree.NewExID(Guid.NewGuid().ToString());//树本身需要一个新的ExID。

                Expressions.Tree.RefreshPreLevelIDs(tree.XmlData.ChildNodes);
                foreach (Expressions.SubPanel sPanel in tree.SubPanels)
                {
                    Expressions.LeafPanel lp = sPanel as Expressions.LeafPanel;

                    if (lp != null)
                    {
                        lp.LoadXmlExID();
                        lp.LoadPreLevelExID();

                        foreach (UIElement ue in lp.BasePanel.Children)
                        {
                            Expressions.Expression ex = ue as Expressions.Expression;

                            if (ex != null)
                            {
                                Expressions.Expression.RebuildAllExIDs(ex);
                            }
                        }
                    }
                }

                tree.RefreshLayout(false);
            }
            #endregion

            Action action = new Action(newEx.ExID, newEx.ParentPanel.BasePanel.Children.IndexOf(newEx),
                newEx.GetType().Name, "InsertExpression", null, newEx.XmlData.OuterXml,
                ActionType.Insert, newEx.ParentPanel.ExID);
            mi.Add(action);

            int newIndex = newEx.ParentPanel.BasePanel.Children.IndexOf(newEx);
            Expressions.Expression preVisibleEx = null;
            for (int i = newIndex - 1; i >= 0; i--)
            {
                Expressions.Expression ex = newEx.ParentPanel.BasePanel.Children[i] as Expressions.Expression;
                if (ex.Visibility == Visibility.Visible)
                {
                    preVisibleEx = ex;
                    break;
                }
            }

            if (preVisibleEx != null && preVisibleEx is Expressions.BaseText)
            {
                Expressions.BaseText preVisibleBt = preVisibleEx as Expressions.BaseText;
                if (preVisibleBt.Indent < newEx.Indent && preVisibleBt.IsCollapsed)
                {
                    Action actUnCollapse = new Action(preVisibleBt.ExID, -1,
                        preVisibleBt.GetType().Name, "IsCollapsed", true.ToString(), false.ToString());

                    preVisibleBt.IsCollapsed = false;

                    mi.Add(actUnCollapse);
                }
            }

            if (newEx is Expressions.BaseText)
            {
                Expressions.BaseText bt = newEx as Expressions.BaseText;
                if (bt.IsHeaderText)
                {
                    newEx.ParentPanel.RefreshAutoNumbersOfBaseText();
                }
            }

            newEx.Editor.Do(mi);

            // 刷新父面板中所有可能存在的树型线。
            //if (newEx.ParentPanel != null && newEx.ParentPanel.Direction == Orientation.Vertical)
            //{
            //    newEx.ParentPanel.RefreshTreeLinesOfHeaderText();
            //}
        }


        public static void PasteExcelDataToGrid()
        {
            String clipboardText = Clipboard.GetText(TextDataFormat.UnicodeText);
            if (clipboardText.Length <= 0)
            {
                MessageBox.Show("剪贴板中没有文本（可以是Excel数据）可以粘贴！", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if (Globals.selectedEditor == null) { return; }
            if (Globals.selectedEditor.SelectedExpression == null)
            {
                MessageBox.Show("请先选中一个普通公式作为粘贴的基准位置！", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            Expressions.Expression curEx = Globals.selectedEditor.SelectedExpression;

            if (curEx is Expressions.SubPanel)
            {
                MessageBox.Show("不能把公式粘贴到“子面板”前面！请先选中一个普通公式作为粘贴的基准位置！", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;//子面板不支持Paste。
            }

            MessageBoxResult result = MessageBox.Show("这一功能是试验功能，可能存在未知的错误！请谨慎使用。在继续之前，请先保存文档。要继续操作，请点击“是(Yes)”。",
                Globals.appName, MessageBoxButton.YesNo, MessageBoxImage.Warning);
            if (result != MessageBoxResult.Yes)
            {
                return;
            }

            if (clipboardText.StartsWith("<Expression") &&
                (clipboardText.EndsWith("</Expression>") || clipboardText.EndsWith("/>")))
            {
                MessageBox.Show("这个方法只能用于将普通文本（或Excel数据表中复制的数据片段）粘贴成网格式，不能用于普通公式的粘贴！",
                    Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            //构造Xml数据。Excel中换行使用“\r\n”。而Excel单元格中文本的换行使用“\n”。
            clipboardText = clipboardText.Replace("\r\n", "\r");

            string[] splitor1 = new string[] { "\r" };
            char[] splitor2 = new char[] { '\t' };

            string[] lines = clipboardText.Split(splitor1, StringSplitOptions.RemoveEmptyEntries);
            int linesLen = lines.Length;
            if (linesLen > 20)
            {
                MessageBoxResult r = MessageBox.Show("行数大于20，这样粘贴成的网格式会比较大，可能使程序变得较慢。要继续吗？", Globals.appName,
                    MessageBoxButton.YesNo, MessageBoxImage.Warning);
                if (r != MessageBoxResult.Yes) return;
            }
            else if (linesLen < 1)
            {
                MessageBox.Show("剪贴板中没有文本可供粘贴成网格式。", Globals.appName,
                    MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            int fstLineCellCount = 0, maxColumns = 0;

            StringBuilder cellsXmlSB = new StringBuilder();

            for (int i = 0; i < linesLen; i++)
            {

                string[] cellStrings = lines[i].Split(splitor2, StringSplitOptions.None);
                if (maxColumns < cellStrings.Length)
                {
                    maxColumns = cellStrings.Length;
                }

                if (i == 0) { fstLineCellCount = maxColumns; }
                else
                {
                    if (fstLineCellCount != maxColumns)
                    {
                        MessageBox.Show("发生意外情况，复制的文本（或Excel数据）各行中的列数不一致！无法继续。\r\n" +
                            "如果文本来自Word表格，请保证任何一个单元格中都没有换行。",
                            Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                        return;
                    }
                }

                for (int ic = 0; ic < cellStrings.Length; ic++)
                {
                    string cellstr, cellXml;
                    cellstr = cellStrings[ic];

                    if (cellstr.Contains('\n') && cellstr.Length > 2 &&
                        cellstr.StartsWith("\"") && cellstr.EndsWith("\""))
                    {
                        cellstr = cellstr.Substring(1, cellstr.Length - 2);

                        //Excel单元格中的数据有换行符时，会自动在单元格文本首尾添加各一个引号；
                        //另，如果带换行符的单元格中，用户在单元格中本身就输入了引号，则用两个引号表示1个引号来转义。
                        //例如，剪贴板中的文本：
                        //"""""8""8
                        //a"
                        //实际上在单元格中显示的是：
                        //""8"8
                        //a
                        //注意：上面行尾的字符8后面都没有写出换行符（“\n”），实际上是存在换行符（“\n”）的。
                        cellstr = cellstr.Replace("\"\"", "\"");
                    }

                    cellstr = ReplaceXmlChars(cellstr);

                    cellXml = "<Expression Type=\"GridPanel\" ";
                    cellXml += "GridX=\"" + ic.ToString() + "\" " + "GridY=\"" + i.ToString() +
                        "\" GridXSpan=\"1\" GridYSpan=\"1\">" +
                        "<Expression Type=\"BaseText\">" +
                        "<Text>" + cellstr + "</Text>" +
                        "</Expression></Expression>";

                    cellsXmlSB.Append(cellXml);
                }
            }

            string gridXml = "<Expression Type=\"Grid\" LinesCount=\"" +
                linesLen.ToString() + "\" ColumnsCount=\"" + maxColumns.ToString() + "\" BorderWidth=\"2\">";

            cellsXmlSB.Append("</Expression>");

            if (curEx.Parent is StackPanel)
            {
                gridXml += cellsXmlSB.ToString();
                if (curEx.XmlData.InsertXml(gridXml, false) == false) return;//粘贴失败。
                StackPanel spanel = curEx.Parent as StackPanel;

                ModifingItem mi = new ModifingItem();


                Expressions.Expression newEx = Expressions.SubPanel.BuildExpression(curEx.XmlData.PreviousSibling,
                           curEx.RootPanel, curEx.ParentPanel, curEx.Editor);

                int index = spanel.Children.IndexOf(curEx);
                spanel.Children.Insert(index, newEx);
                curEx.Editor.SelectedExpression = newEx;

                Action action = new Action(newEx.ExID, newEx.ParentPanel.BasePanel.Children.IndexOf(newEx),
                       newEx.GetType().Name, "InsertExpression", null, newEx.XmlData.OuterXml,
                       ActionType.Insert, newEx.ParentPanel.ExID);
                mi.Add(action);
                newEx.Editor.Do(mi);

                newEx.Editor.IsModified = true;
            }
        }

        /// <summary>
        /// 根据提供的XML文本自动生成一个公式。
        /// </summary>
        /// <param name="before">是否在“curEx”前面的位置插入新公式。</param>
        /// <param name="str">XML文本，必须合乎XML规则。</param>
        /// <param name="curEx">插入新公式的基准位置公式，由“before”参数
        /// 决定是在此公式前面还是后面的位置插入新公式。</param>
        public static Expressions.Expression InsertExpressionByXmlString(bool before, String str,
            LunarPresentation.Expressions.Expression curEx)
        {
            if (str.StartsWith("<Expression") == false ||
                (str.EndsWith("</Expression>") == false && str.EndsWith("/>") == false))
            {
                //MessageBox.Show("剪贴板中不是公式，无法粘贴！", Globals.appName,
                //MessageBoxButton.OK, MessageBoxImage.Warning);

                //原先的设计，文本不是公式就不允许粘贴。现在则作为文本块的内容粘贴。便于摘录文本。

                str = ReplaceXmlChars(str);

                str = "<Expression Type=\"BaseText\"><Text>" + str + "</Text></Expression>";
                //这样就可以直接粘贴成文本块了。
            }

            if (curEx.Parent is StackPanel)
            {
                StackPanel spanel = curEx.Parent as StackPanel;

                if (before)
                {
                    if (curEx.XmlData.InsertXml(str, false) == false) return null;//粘贴失败。
                }
                else
                {
                    if (curEx.XmlData.InsertXml(str, true) == false) return null;//粘贴失败。
                }

                int index = 0;
                if (before)
                {
                    index = spanel.Children.IndexOf(curEx);
                }
                else
                {
                    index = spanel.Children.IndexOf(curEx) + 1;
                }

                Expressions.Expression newExpression;

                if (before)
                {
                    //针对折叠的标题文本块进行处理。
                    System.Xml.XmlAttribute attrIsCollapsed = curEx.XmlData.PreviousSibling.GetAttribute("IsCollapsed");
                    if (attrIsCollapsed != null) { attrIsCollapsed.Value = "False"; }

                    newExpression = Expressions.SubPanel.BuildExpression(curEx.XmlData.PreviousSibling,
                        curEx.RootPanel, curEx.ParentPanel, curEx.Editor);
                }
                else
                {
                    //针对折叠的标题文本块进行处理。
                    System.Xml.XmlAttribute attrIsCollapsed = curEx.XmlData.NextSibling.GetAttribute("IsCollapsed");
                    if (attrIsCollapsed != null) { attrIsCollapsed.Value = "False"; }

                    newExpression = Expressions.SubPanel.BuildExpression(curEx.XmlData.NextSibling,
                        curEx.RootPanel, curEx.ParentPanel, curEx.Editor);
                }

                spanel.Children.Insert(index, newExpression);
                curEx.Editor.SelectedExpression = newExpression;

                newExpression.Editor.IsModified = true;
                return newExpression;
            }

            return null;
        }

        private static String ReplaceXmlChars(String str)
        {
            str = str.Replace("&", "&amp;");//这个要先替换。XML中有五个预先定义的实体。为避免乱码，应使用实体来替换这些字符。

            str = str.Replace("'", "&apos;");//但只有<和&是严格禁止使用的（必须使用实体）。
            str = str.Replace("\"", "&quot;");
            str = str.Replace("<", "&lt;");
            str = str.Replace(">", "&gt;");
            return str;
        }
    }
}
